﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
using FRW.Common.Extensions;
using Money.Plugins;

namespace Money.Interface
{
    public partial class BalanceGraph : GraphControl, IGraph
    {
        public BalanceGraph()
        {
            InitializeComponent();

            HidePanel();

            Name = "Balance Changes";
        }

        public override void UpdateGraph(object sender, DateChangedEventArgs e)
        {
            DrawGraph(e.StartDate, e.EndDate);
        }

        protected override DateTime[] LimitFilterDates(DateTime startDate, DateTime endDate)
        {
            DateTime[] dates = new DateTime[2];

            dates[0] = startDate;
            dates[1] = endDate;

            return dates;
        }

        protected override void updateGraphAxes()
        {
            base.updateGraphAxes();

            if ((_chartArea.AxisX.ScaleView.ViewMaximum - _chartArea.AxisX.ScaleView.ViewMinimum) > 150)
            {
                _chartArea.AxisX.IntervalType = DateTimeIntervalType.Months;
                _chartArea.AxisX.LabelStyle.Format = "dd-MMM-yyyy";
                _chartArea.AxisX.Interval = 1;
            }
            else if ((_chartArea.AxisX.ScaleView.ViewMaximum - _chartArea.AxisX.ScaleView.ViewMinimum) > 30)
            {
                _chartArea.AxisX.IntervalType = DateTimeIntervalType.Weeks;
                _chartArea.AxisX.LabelStyle.IntervalType = DateTimeIntervalType.Weeks;
                _chartArea.AxisX.LabelStyle.Format = "dd-MMM-yyyy";
                _chartArea.AxisX.Interval = 1;
            }
            else
            {
                _chartArea.AxisX.IntervalType = DateTimeIntervalType.Days;
                _chartArea.AxisX.Interval = 1;
                _chartArea.AxisX.LabelStyle.IntervalType = DateTimeIntervalType.Days;
                _chartArea.AxisX.LabelStyle.Format = "dd-MMM-yyyy";
                _chartArea.AxisX.MajorTickMark.IntervalType = DateTimeIntervalType.Weeks;
                _chartArea.AxisX.MajorTickMark.Interval = 1;
            }
        }

        private void DrawGraph(DateTime startDate, DateTime endDate)
        {
            // This is the range required when the data was summarised by week rather than day but day is quick enough to calc and gives a better reflection in the graph
            //var weekDates = Enumerable.Range(0, (endDate.Year - startDate.Year) * 52 + (endDate.Month - startDate.Month + 1))
            //        .Select(weeks => new DateTime(startDate.Year, startDate.Month, 1).AddDays(weeks * 7));

            var dayDates = Enumerable.Range(0, (endDate - startDate).Days)
                    .Select(days => new DateTime(startDate.Year, startDate.Month, 1).AddDays(days));

            var transactions = from transaction in _dataInterface.Transactions.Where(Transactions.InDateRange(startDate, endDate).Compile()) select transaction;

            var incomeTransactions = from filteredTransaction
                                     in transactions
                                     where filteredTransaction.Type != Transaction.TransactionType.Transfer
                                     select filteredTransaction;

            // HACK
            try
            {
                if (_graph.Series != null)
                {
                    _graph.Series.Clear();
                }
            }
            catch
            {
            }
            _graph.Tag = "Categories";

            decimal total = 0;

            foreach (Account account in _dataInterface.Accounts)
            {
                total += account.OpeningBalance;
            }

            var balanceByDay =
                from dr in dayDates
                join transaction in incomeTransactions
                on dr.ToUnixTime() equals transaction.Date.ToUnixTime()
                into joinedGroups
                from joinedGroup in joinedGroups.DefaultIfEmpty(new Transaction() { Date = dr })
                group joinedGroup by joinedGroup.Date into jgp
                select new { Date = jgp.Key, Amount = jgp.Sum(tt => tt.Amount), Balance = (total += jgp.Sum(tt => tt.Amount)) };

            Series series = new Series();

            series.ChartArea = "default";
            series.ChartType = SeriesChartType.Line;
            series.Legend = "default";
            series.Name = "Balance";
            series.SmartLabelStyle.IsOverlappedHidden = false;
            series.BorderWidth = 2;

            _graph.Series.Add(series);

            // set style of series and add the data set
            //_graph.Series[series2.Name]["DrawingStyle"] = "Line";
            _graph.Series[series.Name].Points.DataBind(balanceByDay.ToList(), "Date", "Balance", "");


            // highlight any points in the balance graph below 0 in red
            List<DataPoint> maxValuePoint = series.Points.Where(i => i.YValues[0] < 0).ToList();

            foreach (DataPoint dataPoint in maxValuePoint)
            {
                dataPoint.Color = Color.Red;
            }

            OnFiltered();
        }
    }
}
